package net.oschina.arvin.dbjava.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 反射工具类
 *
 * @author Arvin
 * @time 2017/9/28 14:20
 */
public class ReflectUtils {

    /**
     * 查找指定类型的属性列表
     *
     * @param clazz            类名
     * @param requiredType     字段类型， 如果为空就返回所有的字段
     * @param fieldNamePattern 属性名称匹配规则
     * @return 返回指定类型的属性列表，如果为空就返回所有的字段
     */
    public static List<Field> getDeclaredFields(Class<?> clazz, Class<?> requiredType, String fieldNamePattern) {
        Field[] declaredFields = clazz.getDeclaredFields();
        if (null != declaredFields && declaredFields.length > 0) {
            if (null == requiredType && (null == fieldNamePattern || "".equals(fieldNamePattern.trim())))
                return Arrays.asList(declaredFields);
            List<Field> fields = new ArrayList<Field>();
            for (Field field : declaredFields) {
                if (isAcceptField(field, requiredType, fieldNamePattern)) {
                    fields.add(field);
                }
            }
            return fields;
        }
        return new ArrayList<Field>();
    }

    public static List<Field> getDeclaredFields(Class<?> clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();
        if (null != declaredFields && declaredFields.length > 0) {
            return Arrays.asList(declaredFields);
        }
        return new ArrayList<Field>();
    }

    private static boolean isAcceptField(Field field, Class<?> requiredType, String fieldNamePattern) {
        if (null != requiredType && !requiredType.equals(field.getType())) {
            return false;
        }
        if (null != fieldNamePattern && !"".equals(fieldNamePattern.trim()) && !field.getName().matches(fieldNamePattern)) {
            return false;
        }
        return true;
    }

    /**
     * 设置属性的值
     */
    public static void setFieldValue(Object obj, Field field, Object value) {
        field.setAccessible(true);
        Object realValue = value;
        try {
            Class<?> fieldType = field.getType();
            if (realValue == null) {
                if (fieldType.equals(int.class)) {
                    realValue = 0;
                } else if (fieldType.equals(long.class)) {
                    realValue = 0L;
                } else if (fieldType.equals(short.class)) {
                    realValue = (short) 0;
                } else if (fieldType.equals(double.class)) {
                    realValue = (double) 0;
                } else if (fieldType.equals(float.class)) {
                    realValue = (float) 0;
                } else if (fieldType.equals(byte.class)) {
                    realValue = (byte) 0;
                } else if (fieldType.equals(boolean.class)) {
                    realValue = false;
                }
            } else if (value instanceof Number) {
                Number number = (Number) value;
                if (fieldType.equals(Integer.class) || fieldType.equals(int.class)) {
                    realValue = number.intValue();
                } else if (fieldType.equals(Long.class) || fieldType.equals(long.class)) {
                    realValue = number.longValue();
                } else if (fieldType.equals(Short.class) || fieldType.equals(short.class)) {
                    realValue = number.shortValue();
                } else if (fieldType.equals(Double.class) || fieldType.equals(double.class)) {
                    realValue = number.doubleValue();
                } else if (fieldType.equals(Float.class) || fieldType.equals(float.class)) {
                    realValue = number.floatValue();
                } else if (fieldType.equals(Byte.class) || fieldType.equals(byte.class)) {
                    realValue = number.byteValue();
                } else if (fieldType.equals(Boolean.class) || fieldType.equals(boolean.class)) {
                    realValue = number.intValue() > 0;
                }
            }
            field.set(obj, realValue);
        } catch (IllegalAccessException ignored) {
        }
    }
}
